#include <boost/python/class.hpp>
#include <boost/python/def.hpp>
#include <boost/python/implicit.hpp>
#include <boost/python/module.hpp>
#include <boost/python/overloads.hpp>
#include <boost/python/scope.hpp>
#include "python_plugin.hh"
#include "rs274ngc.hh"
#include "interp_internal.hh"
//#include "taskclass.hh"
#include "initool.hh"
#include "nml_intf/zucglb.h"  // ZUC_INIFILE

namespace bp = boost::python;

#include "array1.hh"

namespace pp = pyplusplus::containers::static_sized;

#include "interp_array_types.hh"  // import toolTable

#include "rcs.hh"           // NML classes, nmlErrorFormat()
#include "nml_intf/zuc.hh"  // ZUC NML
#include "nml_intf/zuc_nml.hh"

extern void zuctask_quit(int sig);
extern ZUC_STAT* zucStatus;
typedef boost::shared_ptr<ZUC_STAT> zucstatus_ptr;
extern int return_int(const char* funcname, PyObject* retval);

// man, is this ugly. I'm taking suggestions to make this better

__attribute__((unused)) static int handle_exception(const char* name)
{
    std::string msg = handle_pyerror();
    printf("%s(): %s\n", name, msg.c_str());
    PyErr_Clear();
    return -1;
}

#define EXPAND(method)                                    \
    int method()                                          \
    {                                                     \
        if (bp::override f = this->get_override(#method)) \
        {                                                 \
            try                                           \
            {                                             \
                return f();                               \
            }                                             \
            catch (bp::error_already_set)                 \
            {                                             \
                return handle_exception(#method);         \
            }                                             \
        }                                                 \
        else                                              \
            return Task::method();                        \
    }

#define EXPAND1(method, type, name)                       \
    int method(type name)                                 \
    {                                                     \
        if (bp::override f = this->get_override(#method)) \
        {                                                 \
            try                                           \
            {                                             \
                return f(name);                           \
            }                                             \
            catch (bp::error_already_set)                 \
            {                                             \
                return handle_exception(#method);         \
            }                                             \
        }                                                 \
        else                                              \
            return Task::method(name);                    \
    }

#define EXPAND2(method, type, name, type2, name2)         \
    int method(type name, type2 name2)                    \
    {                                                     \
        if (bp::override f = this->get_override(#method)) \
        {                                                 \
            try                                           \
            {                                             \
                return f(name, name2);                    \
            }                                             \
            catch (bp::error_already_set)                 \
            {                                             \
                return handle_exception(#method);         \
            }                                             \
        }                                                 \
        else                                              \
            return Task::method(name, name2);             \
    }

typedef pp::array_1_t<ZUC_AXIS_STAT, ZUCMOT_MAX_AXIS> axis_array, (*axis_w)(ZUC_MOTION_STAT&m);
typedef pp::array_1_t<int, ZUCMOT_MAX_DIO> synch_dio_array, (*synch_dio_w)(ZUC_MOTION_STAT&m);
typedef pp::array_1_t<float, ZUCMOT_MAX_AIO> analog_io_array, (*analog_io_w)(ZUC_MOTION_STAT&m);

static axis_array axis_wrapper(ZUC_MOTION_STAT& m) { return axis_array(m.axis); }

static synch_dio_array synch_di_wrapper(ZUC_MOTION_STAT& m) { return synch_dio_array(m.synch_di); }

static synch_dio_array synch_do_wrapper(ZUC_MOTION_STAT& m) { return synch_dio_array(m.synch_do); }

static analog_io_array analog_input_wrapper(ZUC_MOTION_STAT& m) { return analog_io_array(m.analog_input); }

static analog_io_array analog_output_wrapper(ZUC_MOTION_STAT& m) { return analog_io_array(m.analog_output); }

static const char* get_file(ZUC_TASK_STAT& t) { return t.file; }
static const char* get_command(ZUC_TASK_STAT& t) { return t.command; }

static void operator_error(const char* message, int id = 0) { zucOperatorError(id, "%s", message); }
static void operator_text(const char* message, int id = 0) { zucOperatorText(id, "%s", message); }
static void operator_display(const char* message, int id = 0) { zucOperatorDisplay(id, "%s", message); }

#pragma GCC diagnostic push
#if defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)))
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
BOOST_PYTHON_FUNCTION_OVERLOADS(operator_error_overloads, operator_error, 1, 2)
BOOST_PYTHON_FUNCTION_OVERLOADS(operator_text_overloads, operator_text, 1, 2)
BOOST_PYTHON_FUNCTION_OVERLOADS(operator_display_overloads, operator_display, 1, 2)
#pragma GCC diagnostic pop

static const char* ini_filename() { return zuc_inifile; }
